package com.smartfast4j.jsch;

import com.jcraft.jsch.SftpException;
import com.jcraft.jsch.SftpProgressMonitor;
import com.smartfast4j.jsch.bean.SftpUploadResult;
import com.smartfast4j.jsch.util.FileUtil;
import com.smartfast4j.jsch.util.GUIDUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.MalformedURLException;
import java.util.List;
import java.util.Map;

/**
 * 基于Sftp上传实现
 * Created by gacl on 2017/10/16.
 */
public class SftpFileService{

    private static Logger logger = LoggerFactory.getLogger(SftpFileService.class);

    /**
     * 文件上传后的存储方式
     */
    private static final String STORAG_TYPE = "SFTP";

    private SftpClient sftpClient;

    private SftpConfig sftpConfig;

    /**
     *
     *
     * Sftp连接客户端初始化用到的properties配置文件
     * @param sftpConfigFilePath
     */
    public SftpFileService(String sftpConfigFilePath){
        sftpClient = SftpClient.getInstance(sftpConfigFilePath);
        sftpConfig = sftpClient.getConfig();
    }


    public SftpUploadResult uploadFile(String filePath) {
        return uploadFile(filePath,"");
    }


    public SftpUploadResult uploadFile(String filePath, String savePath) {
        File file = new File(filePath);
        return uploadFile(file,savePath);
    }


    public SftpUploadResult uploadFile(InputStream inputStream, String fileName) {
        return upload2Sftp(inputStream,fileName,"");
    }

    /**
     * 一次性上传多个文件
     * @param inputStreamMap 以原始文件名(带后缀,如1.png,2.jpg)为key的输入流Map
     * @return List<UploadResult> 上传结果集合
     */
    public List<SftpUploadResult> uploadFile(Map<String,InputStream> inputStreamMap){
        return uploadFile(inputStreamMap, "");
    }

    /**
     * 一次性上传多个文件
     * @param inputStreamMap 以原始文件名(带后缀,如1.png,2.jpg)为key的输入流Map
     * @param savePath 文件上传后的保存目录
     * @return List<UploadResult> 上传结果集合
     */
    public List<SftpUploadResult> uploadFile(Map<String,InputStream> inputStreamMap,String savePath){
        return uploadFiles2SFtp(inputStreamMap,savePath);
    }

    public SftpUploadResult uploadFile(InputStream inputStream, String fileName, String savePath) {
        return upload2Sftp(inputStream,fileName,savePath);
    }


    public SftpUploadResult uploadFile(File file, String savePath) {
        return upload2Sftp(file,savePath);
    }


    public SftpUploadResult uploadFile(byte[] fileByte, String fileName) {
        return upload2Sftp(fileByte,fileName,"");
    }


    public SftpUploadResult uploadFile(byte[] fileByte, String fileName, String savePath) {
        return upload2Sftp(fileByte,fileName,savePath);
    }

    public SftpUploadResult uploadNetworkFile(String fileUrl) throws MalformedURLException {
        return uploadNetworkFile(fileUrl,"");
    }

    public SftpUploadResult uploadNetworkFile(String fileUrl,String fileExt) throws MalformedURLException {
        //下载网络文件
        byte[] content = FileUtil.downloadNetworkFile(fileUrl);
        String ext;
        if(!FileUtil.isEmpty(fileExt)){
            ext = fileExt;
        }else{
            ext = fileUrl.substring(fileUrl.lastIndexOf(".") + 1).toLowerCase();// 后缀名
        }
        logger.info("ext："+ext);
        String fileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1).toLowerCase()+"."+ext;
        return uploadFile(content,fileName);
    }


    /**
     * 删除文件
     * @param directory 文件所在的目录
     *                  /mydata/app1/uploadFilesManager/gacl/test
     * @param fileName 文件名
     *                 4F2D9F19813CA90B22C6EC7EA769D2EB.jpg
     * @return -1失败,0成功
     */
    public int deleteFile(String directory, String fileName) {
        return sftpClient.delete(directory,fileName);
    }

    /**
     * 删除文件
     * @param savePath 文件存储路径
     *                 /mydata/app1/uploadFilesManager/26323A44A1CA5DF0761769A2A6B6A4A9.png
     * @return -1：失败,0：成功
     */
    public int deleteFile(String savePath) {
        return sftpClient.delete(savePath);
    }

    /**
     * 批量删除
     * @param directory 文件所在目录
     * @param lstFileName 要删除的文件名集合
     * @return 以要删除的文件名为key，删除结果(-1失败,0成功)为value的Map结果集
     */
    public Map<String,Integer> batchDeleteFile(String directory, List<String> lstFileName) {
        return sftpClient.batchDelete(directory, lstFileName);
    }

    /**
     * 批量删除
     * @param lstFileSavePath 要删除的文件路径
     * @return 以要删除的文件名为key，删除结果(-1失败,0成功)为value的Map结果集
     */
    public Map<String,Integer> batchDeleteFile(List<String> lstFileSavePath) {
        return sftpClient.batchDelete(lstFileSavePath);
    }

    public byte[] downloadFile(String fileUrl) {
        try {
            //下载网络文件
            return  FileUtil.downloadNetworkFile(fileUrl);
        }catch (Exception e){
            return null;
        }
    }


    public byte[] downloadFile(String directory, String fileName) {
        InputStream inputStream = sftpClient.download(directory, fileName);
        if(inputStream != null){
            try {
                return FileUtil.input2ByteArray(inputStream);
            } catch (IOException e) {
                logger.error(e.getMessage(),e);
            }
        }
        return null;
    }

    public byte[] downloadAsByte(String downloadFile) {
        return sftpClient.downloadAsByte(downloadFile);
    }


    public void downloadFile(String directory, String fileName, String savePath) {
        sftpClient.download(directory,fileName,savePath);
    }

    public File downloadAsFile(String downloadFile,String savePath) {
        return sftpClient.downloadAsFile(downloadFile, savePath);
    }

    /**
     * 将单个文件上传到SFTP服务器
     * @param inputStream 文件的输入流
     * @param fileName 文件名（带后缀）
     * @param remoteSavePath 远程保存路径
     * @return UploadResult 上传结果
     */
    private SftpUploadResult upload2Sftp(InputStream inputStream, String fileName, final String remoteSavePath){
        Long startTime = System.currentTimeMillis();
        SftpUploadResult uploadFile = new SftpUploadResult();
        String ext = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();// 后缀名
        uploadFile.setOriginalFileName(fileName);
        uploadFile.setFileSuffix(ext);
        String newFileName = GUIDUtil.genRandomGUID()+"."+ext;
        uploadFile.setNewFileName(newFileName);
        try {
            upload2Sftp(inputStream, uploadFile, newFileName, remoteSavePath);
        } catch (Exception ex) {
            uploadFile.setIsUploadSuccess(false);//上传失败
            logger.error("将文件上传到SFTP服务器失败！", ex);
        }
        Long endTime = System.currentTimeMillis();
        uploadFile.setUseTime(endTime-startTime);
        return uploadFile;
    }

    /**
     * 将单个multipartFile文件上传到SFTP服务器
     * @param file 需要上传的文件
     * @param remoteSavePath 文件存放目录
     * @return UploadResult 上传结果
     */
    private SftpUploadResult upload2Sftp(File file, final String remoteSavePath){
        Long startTime = System.currentTimeMillis();
        SftpUploadResult uploadFile = new SftpUploadResult();
        String fileName = file.getName();// 文件名
        String ext = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();// 后缀名
        uploadFile.setOriginalFileName(fileName);
        uploadFile.setFileSuffix(ext);
        String newFileName = GUIDUtil.genRandomGUID()+"."+ext;
        uploadFile.setNewFileName(newFileName);
        try {
            FileInputStream fileInputStream = new FileInputStream(file);
            upload2Sftp(fileInputStream,uploadFile,newFileName,remoteSavePath);
        } catch (IOException ex) {
            uploadFile.setIsUploadSuccess(false);//上传失败
            logger.error("将文件上传到SFTP服务器失败！", ex);
        }
        Long endTime = System.currentTimeMillis();
        uploadFile.setUseTime(endTime-startTime);
        return uploadFile;
    }

    /**
     * 将单个文件上传到SFTP服务器
     * @param fileByte 文件的二进制数据
     * @param fileName 文件名（带后缀）
     * @param remoteSavePath 远程保存路径
     * @return UploadResult 上传结果
     */
    private SftpUploadResult upload2Sftp(byte[] fileByte, String fileName,final String remoteSavePath){
        Long startTime = System.currentTimeMillis();
        SftpUploadResult uploadFile = new SftpUploadResult();
        String ext = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();// 后缀名
        uploadFile.setOriginalFileName(fileName);
        uploadFile.setFileSuffix(ext);
        String newFileName = GUIDUtil.genRandomGUID()+"."+ext;
        uploadFile.setNewFileName(newFileName);
        try {
            InputStream in = new ByteArrayInputStream(fileByte);
            upload2Sftp(in,uploadFile,newFileName,remoteSavePath);
        } catch (Exception ex) {
            uploadFile.setIsUploadSuccess(false);//上传失败
            logger.error("将文件上传到SFTP服务器失败！", ex);
        }
        Long endTime = System.currentTimeMillis();
        uploadFile.setUseTime(endTime-startTime);
        return uploadFile;
    }

    /**
     * 将单个文件上传到SFTP服务器
     * @param is 文件输入流
     * @param uploadFile 上传后的响应对象，里面封装了返回的文件上传信息
     * @param nFileName 新文件名
     * @param remoteSavePath 文件存放目录
     */
    private void upload2Sftp(InputStream is, final SftpUploadResult uploadFile, final String nFileName, final String remoteSavePath) {
        try {
            String remotePath;//存放目录
            logger.info("将文件上传到FTP服务器");
            if(FileUtil.isEmpty(remoteSavePath)){
                remotePath = sftpConfig.getWorkPath();
                uploadFile.getExtFieldMap().put("remoteSavePath",sftpConfig.getWorkPath());
            }else{
                if(remoteSavePath.startsWith("/")){
                    remotePath = sftpConfig.getWorkPath()+remoteSavePath;
                    uploadFile.getExtFieldMap().put("remoteSavePath",sftpConfig.getWorkPath()+remoteSavePath);
                }else{
                    remotePath = sftpConfig.getWorkPath()+"/"+remoteSavePath;
                    uploadFile.getExtFieldMap().put("remoteSavePath",sftpConfig.getWorkPath()+"/"+remoteSavePath);
                }
            }
            /**
             * 将文件上传到FTP服务器
             */
            sftpClient.uploadFile(is, nFileName, remotePath, new SftpProgressMonitor() {
                private long transfered;

                @Override
                public void init(int i, String s, String s1, long l) {
                    uploadFile.setSavePath(s1);
                    logger.info("初始化上传,要上传的文件是:" + s + ",目标存放路径是:" + s1);
                }

                @Override
                public boolean count(long l) {
                    transfered = transfered + l;
                    logger.info("当前已经上传了: " + transfered + " bytes(字节)");
                    return true;
                }

                @Override
                public void end() {
                    if (!FileUtil.isEmpty(remoteSavePath)) {
                        if (remoteSavePath.startsWith("/")) {
                            uploadFile.setFileUrl(sftpConfig.getFileServerDomain() + remoteSavePath + "/" + nFileName);
                        } else {
                            uploadFile.setFileUrl(sftpConfig.getFileServerDomain() + "/" + remoteSavePath + "/" + nFileName);
                        }
                    } else {
                        uploadFile.setFileUrl(sftpConfig.getFileServerDomain() + "/" + nFileName);
                    }
                    uploadFile.setIsUploadSuccess(true);//上传成功
                    uploadFile.setStorageType(STORAG_TYPE);//文件上传存储方式
                    logger.info("将文件上传到SFTP服务器,上传的文件信息：" + uploadFile);
                }
            });
        } catch (Exception ex) {
            uploadFile.setIsUploadSuccess(false);//上传失败
            logger.error("将文件上传到SFTP服务器失败！", ex);
        }
    }

    /**
     * 将多个文件上传到SFTP服务器
     * @param inputStreamMap 需要上传的文件输入流Map
     * @param remoteSavePath 保存路径
     * @return List<SftpUploadResult> null则表示全部上传失败
     */
    private List<SftpUploadResult> uploadFiles2SFtp(Map<String,InputStream> inputStreamMap, final String remoteSavePath) {
        try {
           return sftpClient.uploadFiles(inputStreamMap,remoteSavePath);
        } catch (SftpException e) {
            e.printStackTrace();
            return null;
        }
    }

}
